package com.doubao.common.config;

import com.doubao.common.utils.RedisTemplateFactory;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.SimpleCacheErrorHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.Assert;

import java.time.Duration;

/**
 * Redis配置类 - 优化版
 * 增加了错误处理，确保Redis故障不会影响应用正常运行
 */
@Configuration
@EnableCaching
@Slf4j
public class RedisConfig implements CachingConfigurer {

    /**
     * 配置Redis连接工厂
     * 使用RedisTemplateFactory创建的连接工厂
     */
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        try {
            // 获取RedisTemplateFactory中的连接工厂
            RedisConnectionFactory factory = RedisTemplateFactory.getRedisTemplate().getConnectionFactory();
            Assert.notNull(factory, "RedisConnectionFactory must not be null");
            log.info("使用RedisTemplateFactory创建的连接工厂");
            return factory;
        } catch (Exception e) {
            log.error("获取Redis连接工厂失败，应用将使用降级策略: {}", e.getMessage());
            // 返回LettuceConnectionFactory的实例，但不会真正连接Redis
            return RedisTemplateFactory.getRedisTemplate().getConnectionFactory();
        }
    }

    /**
     * 配置Redis模板
     * 使用RedisTemplateFactory创建的RedisTemplate
     */
    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<String, Object> redisTemplate() {
        try {
            log.info("使用RedisTemplateFactory创建的RedisTemplate");
            // 直接返回RedisTemplateFactory创建的模板
            return RedisTemplateFactory.getRedisTemplate();
        } catch (Exception e) {
            log.error("获取RedisTemplate失败，应用将使用降级策略: {}", e.getMessage());
            // 创建一个空的模板，让应用不会因为Redis问题而崩溃
            return new RedisTemplate<>();
        }
    }

    /**
     * 配置缓存管理器
     * 使用更短的TTL和快速失败策略
     */
    @Bean
    @Primary
    @ConditionalOnMissingBean(CacheManager.class)
    public CacheManager cacheManager() {
        log.info("初始化CacheManager");

        try {
            // 获取RedisTemplateFactory创建的连接工厂
            RedisConnectionFactory factory = redisConnectionFactory();

            RedisSerializer<String> redisSerializer = new StringRedisSerializer();
            GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();

            // 配置序列化，使用更短的TTL
            RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                    // 设置缓存有效期为10分钟，降低TTL减少Redis负担
                    .entryTtl(Duration.ofMinutes(10))
                    .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                    .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jsonRedisSerializer))
                    .disableCachingNullValues();

            return RedisCacheManager.builder(factory)
                    .cacheDefaults(config)
                    .transactionAware() // 启用事务感知
                    .build();
        } catch (Exception e) {
            log.error("创建CacheManager失败，应用将使用降级策略: {}", e.getMessage());
            // 返回一个不使用Redis的缓存管理器
            return RedisCacheManager.builder(redisConnectionFactory())
                    .cacheDefaults(RedisCacheConfiguration.defaultCacheConfig()
                            .entryTtl(Duration.ofMinutes(5)))
                    .build();
        }
    }

    /**
     * 配置缓存错误处理器
     * 确保缓存操作失败不会影响应用主流程
     */
    @Override
    @Bean
    public CacheErrorHandler errorHandler() {
        // 使用自定义的错误处理器，只记录错误但不抛出异常
        return new ResilientCacheErrorHandler();
    }

    /**
     * 自定义的缓存错误处理器
     * 确保缓存操作失败不会阻塞主流程
     */
    private static class ResilientCacheErrorHandler extends SimpleCacheErrorHandler {
        @Override
        public void handleCacheGetError(RuntimeException exception, org.springframework.cache.Cache cache, Object key) {
            log.warn("Redis缓存读取异常 [{}]: {}", cache.getName(), exception.getMessage());
            // 不向上抛出异常，让应用继续执行
        }

        @Override
        public void handleCachePutError(RuntimeException exception, org.springframework.cache.Cache cache, Object key, Object value) {
            log.warn("Redis缓存写入异常 [{}]: {}", cache.getName(), exception.getMessage());
            // 不向上抛出异常，让应用继续执行
        }

        @Override
        public void handleCacheEvictError(RuntimeException exception, org.springframework.cache.Cache cache, Object key) {
            log.warn("Redis缓存删除异常 [{}]: {}", cache.getName(), exception.getMessage());
            // 不向上抛出异常，让应用继续执行
        }

        @Override
        public void handleCacheClearError(RuntimeException exception, org.springframework.cache.Cache cache) {
            log.warn("Redis缓存清空异常 [{}]: {}", cache.getName(), exception.getMessage());
            // 不向上抛出异常，让应用继续执行
        }
    }

    @PostConstruct
    public void logConfigInfo() {
        log.info("Redis优化配置类已加载，启用了故障转移和降级策略");
    }
}